package com.mt.roll.opcua.s7.my.s7connector.type;

import com.mt.roll.opcua.s7.my.s7connector.api.utils.ByteUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import java.util.HashMap;
import java.util.Map;

public enum PlcVar {
    //单体变量
    BOOL("BOOL",TransportSize.BOOL,1,false),
    BYTE("BYTE",TransportSize.BYTE,2,false),
    WORD("WORD",TransportSize.WORD,3,false),
    DWORD("DWORD",TransportSize.DWORD,4,false),
    LWORD("LWORD",TransportSize.LWORD,5,false),
    INT("INT",TransportSize.INT,6,false),
    UINT("UINT",TransportSize.UINT,7,false),
    SINT("SINT",TransportSize.SINT,8,false),
    USINT("USINT",TransportSize.USINT,9,false),
    DINT("DINT",TransportSize.DINT,10,false),
    UDINT("UDINT",TransportSize.UDINT,11,false),
    LINT("LINT",TransportSize.LINT,12,false),
    ULINT("ULINT",TransportSize.ULINT,13,false),
    REAL("REAL",TransportSize.REAL,14,false),
    LREAL("LREAL",TransportSize.LREAL,15,false),
    CHAR("CHAR",TransportSize.CHAR,16,false),
    WCHAR("WCHAR",TransportSize.WCHAR,17,false),
    STRING("STRING",TransportSize.STRING,18,false),
    WSTRING("WSTRING",TransportSize.WSTRING,19,false),
    TIME("TIME",TransportSize.TIME,20,false),
    LTIME("LTIME",TransportSize.LTIME,21,false),
    DATE("DATE",TransportSize.DATE,22,false),
    TIME_OF_DAY("TIME_OF_DAY",TransportSize.TIME_OF_DAY,23,false),
    TOD("TOD",TransportSize.TOD,24,false),
    DATE_AND_TIME("DATE_AND_TIME",TransportSize.DATE_AND_TIME,25,false),
    DT("DT",TransportSize.DT,26,false),
    DTL("DTL",TransportSize.DTL,27,false),

    //todo  Array 再搞一搞。
    BOOL_Array("BOOL",TransportSize.BOOL,1,true),
    BYTE_Array("BYTE",TransportSize.BYTE,2,true),
    WORD_Array("WORD",TransportSize.WORD,3,true),
    DWORD_Array("DWORD",TransportSize.DWORD,4,true),
    CHAR_Array("CHAR",TransportSize.CHAR,5,true),
    SINT_Array("SINT",TransportSize.SINT,6,true),
    INT_Array("INT",TransportSize.INT,7,true),
    DINT_Array("DINT",TransportSize.DINT,8,true),
    UINT_Array("UINT",TransportSize.UINT,9,true),
    USINT_Array("USINT",TransportSize.USINT,10,true),
    UDINT_Array("UDINT",TransportSize.UDINT,11,true),
    STRING_Array("STRING",TransportSize.STRING,12,true),
    ;
    private static final Logger logger = LoggerFactory.getLogger(TransportSize.class);

    private static final Map<TransportSize, PlcVar> map;
    static {
        map = new HashMap<>();
        for (PlcVar value : PlcVar.values()) {
            if(!value.isArray){
                map.put(value.getTransportSize(), value);
            }
        }
    }
    public static PlcVar valueOf(TransportSize transportSize){
        return map.get(transportSize);
    }


    private String name;
    private TransportSize transportSize;
    private Integer dataType;
    private boolean isArray;


    PlcVar(String name , TransportSize transportSize, Integer dataType,Boolean isArray){
        this.name = name;
        this.transportSize = transportSize;
        this.dataType = dataType;
        this.isArray = isArray;
    }

    public String getName() {
        return name;
    }
    public TransportSize getTransportSize() {
        return transportSize;
    }

    public boolean isArray() {
        return isArray;
    }

    public byte[] toBytes(Object value){
        //todo here 扩展数组 toBytes
        if(!isArray){
            byte[] res = null;
            switch (dataType) {
                case 1:
                    res = ByteUtils.boolToBytes((boolean)value);
                    break;
                case 2:
                    //ByteUtils.setbytes(Byte.valueOf((byte) 0xFF))
                    res = ByteUtils.setbytes(Byte.valueOf((byte) value));
                    break;
                case 3:
                    //ByteUtils.wordToBytes(Short.valueOf("-55"))
                    res = ByteUtils.wordToBytes(Short.valueOf(value.toString()));
                    break;
                case 4:
                    //ByteUtils.dwordToBytes(99)
                    res = ByteUtils.dwordToBytes((int)value);
                    break;
                case 5:
                    //null
                    break;
                case 6:
                    //ByteUtils.intToBytes(-99)
                    res = ByteUtils.intToBytes((int)value);
                    break;
                case 7:
                    //ByteUtils.uintToBytes(9)
                    res = ByteUtils.uintToBytes((int)value);
                    break;
                case 8:
                    //ByteUtils.sintToBytes(-9)
                    res =ByteUtils.sintToBytes((int)value);
                    break;
                case 9:
                    //ByteUtils.usintToBytes(9);
                    res =ByteUtils.usintToBytes((int)value);
                    break;
                case 10:
                    //ByteUtils.dintToBytes(-999)
                    res =ByteUtils.dintToBytes((int)value);
                    break;
                case 11:
                    //ByteUtils.udintToBytes(99)
                    res =ByteUtils.udintToBytes((int)value);
                    break;
                case 12:
                    //待补充
                    break;
                case 13:
                    //待补充
                    break;
                case 14:
                    //ByteUtils.realToBytes(Float.valueOf("-11.2"))
                    res =ByteUtils.realToBytes(Float.valueOf(value.toString()));
                    break;
                case 15:
                    //ByteUtils.lrealToBytes(Double.parseDouble("-111.1"));
                    res =ByteUtils.lrealToBytes(Double.parseDouble(value.toString()));
                    break;
                case 16:
                    //ByteUtils.charToBytes('b')
                    res =ByteUtils.charToBytes((char)value);
                    break;
                case 17:
                    //ByteUtils.wcharToBytes('菜')
                    res =ByteUtils.wcharToBytes((char)value);
                    break;
                case 18:
                    //String s = "你好啊";
                    //ByteUtils.strToBytes(s);
                    res = ByteUtils.strToBytes(value.toString());
                    break;
                case 19:
                    //待补充
                    break;
                case 20:
                    //不常用 待补充
                    break;
                case 21:
                    //不常用
                    break;
                case 22:
                    //不常用
                    break;
                case 23:
                    ////不常用
                    break;
                case 24:
                    ////不常用
                    break;
                case 25:
                    //不常用
                    break;
                case 26:
                    //不常用
                    break;
                case 27:
                    //不常用
                    break;
                default:
                    //什么也不做
                    break;
            }
            return res;
        }else {
            byte[] res = null;
            switch (dataType) {
                case 1:
//                    boolean[] booleanArray = new boolean[2];
//                    booleanArray[0] = true;
//                    booleanArray[1] = true;
//                    ByteUtils.booleanArrayToBytes(booleanArray)
                    res = ByteUtils.booleanArrayToBytes((boolean[]) value);
                    break;
                case 2:
//                    byte[] write_byteArrays = new byte[2];
//                    write_byteArrays[0] = 1;
//                    write_byteArrays[1] = 2;
//
                    res = (byte[]) value;
                    break;
                case 3:
//                    short[] shortArrays_content = new short[2];
//                    shortArrays_content[0] = 1;
//                    shortArrays_content[1] = -1;
//
                    res = ByteUtils.wordArrayToBytes((short[]) value);
                    break;
                case 4:
//                  int[] intArrays_content = new int[2];
//                  intArrays_content[0] = 1;
//                  intArrays_content[1] = -1;
//
                    res = ByteUtils.dwordArrayToBytes((int[]) value);
                    break;
                case 5:
//                  char[] charArrays_content = new char[2];
//                  charArrays_content[0] = '1';
//                  charArrays_content[1] = 'b';
//
                    res = ByteUtils.charArrayToBytes((char[]) value);
                    break;
                case 6:
//                  int[] sintArrays_content = new int[2];
//                  sintArrays_content[0] = 1;
//                  sintArrays_content[1] = -1;
//
                    res = ByteUtils.sintArrayToBytes((int[]) value);
                    break;
                case 7:
//                  int[] iintArrays_content = new int[2];
//                  iintArrays_content[0] = 12;
//                  iintArrays_content[1] = -21;
//
                    res = ByteUtils.intArrayToBytes((int[]) value);
                    break;
                case 8:
//                  int[] dintArrays_content = new int[2];
//                  dintArrays_content[0] = 12;
//                  dintArrays_content[1] = -21;
//
                    res = ByteUtils.dintArrayToBytes((int[]) value);
                    break;
                case 9:
//                    int[] uintArrays_content = new int[3];
//                    uintArrays_content[0] = 12;
//                    uintArrays_content[1] = 99;
//                    uintArrays_content[2] = 1;
                    res = ByteUtils.uintArrayToBytes((int[]) value);
                    break;
                case 10:
//                    int[] usintArrays_content = new int[3];
//                    usintArrays_content[0] = 12;
//                    usintArrays_content[1] = 99;
//                    usintArrays_content[2] = 1;
                    res = ByteUtils.usintArrayToBytes((int[]) value);
                    break;
                case 11:
//                    int[] udintArrays_content = new int[3];
//                    udintArrays_content[0] = 12;
//                    udintArrays_content[1] = 99;
//                    udintArrays_content[2] = 1;
                    res = ByteUtils.udintArrayToBytes((int[]) value);
                    break;
                case 12:

                    break;
                default:
                    //什么也不做
                    break;
            }
            return res;
        }
    }

    //todo here 把 read 和 write操作都封装一下 然后 和 toByte 和 toObject 整合
    /**
     * PlcVar(byte[])  转  java对象    对照表
     * 单体变量
     * Bool       ===>      Boolean
     * LREAL      ===>      Double
     * REAL       ===>      Float
     * DATE       ===>      String(yyyy-MM-dd 这种形式的类型)
     * DTL        ===>      String("年-月-日-工作日-时-分-秒" 这种格式)
     * TIME       ===>      Integer(单位 ms)
     * USINT      ===>      Integer
     * SINT       ===>      Integer
     * UINT       ===>      Integer
     * INT        ===>      Integer
     * DINT       ===>      Integer
     * UINT       ===>      Long
     * Byte       ===>      Integer(有符号)(默认)
     *                     Integer(无符号)(后续扩展)
     * Char       ===>      Character
     * WChar      ===>      Character
     * String     ===>      String                    //注意： String类型 不能用枚举类里的 toObject() / toBytes() 的方法，具体方式看Demo


     * 数组变量
     * BoolArray      ===>      List<Boolean>
     * ByteArray      ===>      List<Byte>
     * WordArray      ===>      List<Integer>
     * DWordArray     ===>      List<Integer>
     * CharArray      ===>      List<Character>
     * SIntArray      ===>      List<Integer>
     * IntArray       ===>      List<Integer>
     * DIntArray      ===>      List<Integer>
     * UIntArray      ===>      List<Integer>
     * USIntArray     ===>      List<Integer>
     * UDIntArray     ===>      List<Long>
     * StringArray    ===>      List<String>         //注意： String类型 不能用枚举类里的 toObject() / toBytes() 的方法，具体方式看Demo
     *
     *
     * */
    public Object toObject(byte[] value) throws ParseException, UnsupportedEncodingException {
        if(!isArray){
            Object res = null;
            switch (dataType) {
                case 1:
                    //
                    res = ByteUtils.toBoolean(value);
                    break;
                case 2:
                    //
                    res = ByteUtils.toInt(value[0]);
                    break;
                case 3:
                    //
                    res = ByteUtils.toInt(value[0],value[1]);
                    break;
                case 4:
                    //
                    res = ByteUtils.toInt(value[0],value[1],value[2],value[3]);
                    break;
                case 5:
                    //null
                    break;
                case 6:
                    //
                    res = ByteUtils.toUInt(value[0],value[1]);
                    break;
                case 7:
                    //
                    res = ByteUtils.toUInt(value[0],value[1]);
                    break;
                case 8:
                    //
                    res = ByteUtils.toUInt(value[0]);
                    break;
                case 9:
                    //
                    res = ByteUtils.toUInt(value[0]);
                    break;
                case 10:
                    //
                    res = ByteUtils.toInt(value[0],value[1],value[2],value[3]);
                    break;
                case 11:
                    //
                    res = ByteUtils.toInt(value[0],value[1],value[2],value[3]);

                    break;
                case 12:
                    //

                    break;
                case 13:
                    //

                    break;
                case 14:
                    //
                    res = ByteUtils.realbytesToFloat(value);
                    break;
                case 15:
                    //ByteUtils.lrealbytesToDouble(lreal)
                    res = ByteUtils.lrealbytesToDouble(value);
                    break;
                case 16:
                    //
                    res = ByteUtils.toChar(value);
                    break;
                case 17:
                    //
                    res = ByteUtils.toChar(value);
                    break;
                case 18:
                    //
                    res = ByteUtils.toStr(value);
                    break;
                case 19:
                    //

                    break;
                case 20:
                    //
                    res = ByteUtils.toInt(value[0], value[1], value[2], value[3]);
                    break;
                case 21:
                    //

                    break;
                case 22:
                    //

                    Long aLong = Long.valueOf(ByteUtils.toInt(value[0], value[1]).toString());
                    String s = ByteUtils.addDate("1990-01-01", aLong);
                    res = s;
                    break;
                case 23:
                    //

                    break;
                case 24:
                    //

                    break;
                case 25:
                    //

                    break;
                case 26:
                    //

                    break;
                case 27:
                    //
                    byte[] year = new byte[2];
                    year[0] = value[0];
                    year[1] = value[1];
                    Integer yearInt = ByteUtils.toInt(year[0], year[1]);
                    Integer monthInt = ByteUtils.toInt(value[2]);
                    Integer dayInt = ByteUtils.toInt(value[3]);
                    Integer worddayInt = ByteUtils.toInt(value[4]);
                    Integer hourInt = ByteUtils.toInt(value[5]);
                    Integer minuInt = ByteUtils.toInt(value[6]);
                    Integer secondInt = ByteUtils.toInt(value[7]);
                    res = yearInt+"-"+monthInt+"-"+dayInt+"-"+worddayInt+"-"+hourInt+"-"+minuInt+"-"+secondInt;
                    break;
                default:
                    //什么也不做
                    break;
            }
            return res;
        }else {
            Object res = null;
            switch (dataType) {
                case 1:
                    //
                    res = ByteUtils.toBoolArray(value);
                    break;
                case 2:
                    //
                    res = ByteUtils.toByteArray(value);
                    break;
                case 3:
                    //
                    res = ByteUtils.toWordArray(value);
                    break;
                case 4:
                    //
                    res = ByteUtils.toDWordArray(value);
                    break;
                case 5:
                    //
                    res = ByteUtils.toCharArray(value);
                    break;
                case 6:
                    //
                    res =ByteUtils.toSIntArray(value);
                    break;
                case 7:
                    res = ByteUtils.toIntArray(value);
                    break;
                case 8:
                    res = ByteUtils.toDIntArray(value);
                    break;
                case 9:
                    res = ByteUtils.toUIntArray(value);
                    break;
                case 10:
                    res = ByteUtils.toUSIntArray(value);
                    break;
                case 11:
                    res = ByteUtils.toUDIntArray(value);
                    break;

                case 12:
                    //后续有其他数组类型 ，再补充好了，先列出一些常用的。
                    //本来这里 是吧byte[] => String[] 的，但是这里拿不到 String[] 的length 和 strSize, 所以就不在这里解析了在外面解析

                    break;
                default:
                    //什么也不做
                    break;
            }
            return res;
        }
    }

    /**
     * area               :DB块  或者其他块
     * areaNumber         :数据块编号  DB3
     * byteOffset         :字节偏移量
     * byteOffset         :比特偏移量（不填就是0  ，差不多只有读bool类型才会用到）
     * length             :长度（1 代表单个变量 ，2/3/4  代表读一个数组。）
     * */



}
